import uuid
import asyncio
import json
import threading, queue
from concurrent.futures import ThreadPoolExecutor, TimeoutError

from main.asr import ASR
from main.tts import TTS
from main.llm import LLM
from main.vad import VAD

class ConectionHandle:
    def __init__(self, _vad: VAD, _asr: ASR, _llm: LLM, _tts: TTS):
        self.vad = _vad
        self.asr = _asr
        self.llm = _llm
        self.tts = _tts
        
         # vad相关变量
        self.client_audio_buffer = bytearray()
        self.client_have_voice = False
        self.client_have_voice_last_time = 0.0
        self.client_no_voice_last_time = 0.0
        self.client_voice_stop = False
        
        # 客户端状态相关
        self.client_abort = False

        # asr相关变量
        self.asr_audio = []
        self.asr_server_receive = True

        # llm相关变量
        self.llm_finish_task = False
        # self.dialogue = Dialogue()

        # tts相关变量
        self.tts_first_text_index = -1
        self.tts_last_text_index = -1

        # 线程任务相关
        self.loop = asyncio.get_event_loop()
        self.stop_event = threading.Event()
        self.tts_queue = queue.Queue()
        self.audio_play_queue = queue.Queue()
        self.executor = ThreadPoolExecutor(max_workers=10)
        
        self.websocket = None
        self.session_id = None
    
    async def handle_connection(self, websocket):
        # 认证通过,继续处理
        self.websocket = websocket
        self.session_id = str(uuid.uuid4())
        
        # 连接成功发送欢迎消息
        welcome_msg = { "content":"welcome!", }
        await self.websocket.send(json.dumps(welcome_msg))
        
        try:
            async for message in self.websocket:
                await self._router_message(message=message)
        except:
            print("❌❌❌客户端断开连接")
    
    # 分叉处理不同消息
    async def _router_message(self, message):
        if isinstance(message, str):
            await self.handletextMsg(text=message)
        elif isinstance(message, bytes):
            await self.handleAudioMsg(message)

    # 文本消息
    async def handletextMsg(self, text):
        pass
    
    async def no_voice_close_connect(self):
        pass
     
    async def reset_vad_states(self):
        pass
    
    async def reset_vad_states(self):
        pass
      
    #1️⃣################# ⬇️⬇️⬇️ ASR流程 ######################
    # 语音消息
    async def handleAudioMsg(self, audio):
        if not self.asr_server_receive:
            print(f"前期数据处理中，暂停接收")
            return
        
        # 是否有声音
        have_voice = self.vad.is_vad(self, audio)
        # 如果没声音，丢弃
        if have_voice == False and self.client_have_voice == False:
            await self.no_voice_close_connect()
            self.asr_audio.append(audio)
            # 保留最新的10帧音频内容，解决ASR句首丢字问题
            self.asr_audio = self.asr_audio[-10]
            return
        
        self.client_no_voice_last_time = 0.0
        self.asr_audio.append(audio)
        
        # 如果本段有声音，且已经停止了
        if self.client_voice_stop:
            self.client_abort = False
            self.asr_server_receive = False
            
            if len(self.asr_audio) < 15:
                # 允许接受
                self.asr_server_receive = True
            else:
                # 执行识别操作
                text, _ = await self.asr.speech_to_text(self.asr_audio, self.session_id)
                text_len = self.remove_punctuation_and_length(text)
                if text_len > 0:
                    await self.startToChat(text=text)
                else:
                    # 允许接受
                    self.asr_server_receive = True
            
            # 执行一轮后清理状态和数据
            self.asr_audio.clear()
            self.reset_vad_states()
    #1️⃣################# ⬆️⬆️⬆️ ASR流程 ######################
    
    #2️⃣################# ⬇️⬇️⬇️ LLM 流程 ######################
    async def send_stt_message(self, text):
        """发送 STT 状态消息"""
        info_msg = { "type": "llm", "text": "😊", "emotion": "happy", "session_id": self.session_id, }
        await self.websocket.send(json.dumps(info_msg))
        await self.send_tts_message("start")
    
    # 发送消息
    async def send_tts_message(self, state: str, text: str = None):
        """发送 TTS 状态消息"""
        message = {"type": "tts", "state": state, "session_id": self.session_id}
        if text is not None:
            message["text"] = text

        # TTS播放结束
        if state == "stop":
            # 如果是结束播放提示音
            print("TTS播放结束")
            # 清除服务端讲话状态
            # self.clearSpeakStatus()

        # 发送消息到客户端
        await self.websocket.send(json.dumps(message))
        
        # asr流程完毕，拿到asr文本走llm流程
        # 根据asr数据请求llm数据，等待ai回复
        self.chat(text=text)
         
    async def startToChat(self, text):
        # 先执行意图分析
        
        # 执行正常聊天
        # 意图未被处理，继续常规聊天流程
        await self.send_stt_message(text)
        self.chat(text=text)
        # self.executor.submit(self.chat, text)
    
    def chat(self, text):
        response_message = []
        processed_chars = 0  # 跟踪已处理的字符位置
        
        try:
            # 大模型回复消息
            llm_responses = self.llm.response(self.session_id, text)
        except Exception as e:
            print(f"LLM 处理出错: {e}")
            return None
        
        self.llm_finish_task = False
        text_index = 0
        for content in llm_responses:
            response_message.append(content)
            if self.client_abort:
                break

            # 合并当前全部文本并处理未分割部分
            full_text = "".join(response_message)
            current_text = full_text[processed_chars:]  # 从未处理的位置开始

            # 查找最后一个有效标点
            punctuations = ("。", "？", "！", "；", "：")
            last_punct_pos = -1
            for punct in punctuations:
                pos = current_text.rfind(punct)
                if pos > last_punct_pos:
                    last_punct_pos = pos

            # 找到分割点则处理
            if last_punct_pos != -1:
                segment_text_raw = current_text[: last_punct_pos + 1]
                segment_text = self.get_string_no_punctuation_or_emoji(segment_text_raw)
                if segment_text:
                    text_index += 1
                    self.recode_first_last_text(segment_text, text_index)
                    future = self.executor.submit(
                        self.speak_and_play, segment_text, text_index
                    )
                    self.tts_queue.put(future)
                    processed_chars += len(segment_text_raw)  # 更新已处理字符位置
        
        # 处理最后剩余的文本
        full_text = "".join(response_message)
        remaining_text = full_text[processed_chars:]
        if remaining_text:
            segment_text = self.get_string_no_punctuation_or_emoji(remaining_text)
            if segment_text:
                text_index += 1
                self.recode_first_last_text(segment_text, text_index)
                future = self.executor.submit(
                    self.speak_and_play, segment_text, text_index
                )
                self.tts_queue.put(future)

        self.llm_finish_task = True
        self.dialogue.put(Message(role="assistant", content="".join(response_message)))
        print(json.dumps(self.dialogue.get_llm_dialogue(), indent=4, ensure_ascii=False))
        return True
    #2️⃣################# ⬆️⬆️⬆️ TTS聊天流程 ######################
    
    #3️⃣################# ⬇️⬇️⬇️ TTS聊天流程 ######################
    
    #3️⃣################# ⬆️⬆️⬆️ TTS聊天流程 ######################
    
    def recode_first_last_text(self, text, text_index=0):
        if self.tts_first_text_index == -1:
            print(f"大模型说出第一句话: {text}")
            self.tts_first_text_index = text_index
        self.tts_last_text_index = text_index
        
    # 移除特殊字符
    def remove_punctuation_and_length(self, text):
        # 全角符号和半角符号的Unicode范围
        full_width_punctuations = ("！＂＃＄％＆＇（）＊＋，－。／：；＜＝＞？＠［＼］＾＿｀｛｜｝～")
        half_width_punctuations = r'!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~'
        space = " "  # 半角空格
        full_width_space = "　"  # 全角空格

        # 去除全角和半角符号以及空格
        result = "".join(
            [
                char
                for char in text
                if char not in full_width_punctuations
                and char not in half_width_punctuations
                and char not in space
                and char not in full_width_space
            ]
        )

        if result == "Yeah":
            return 0, ""
        return len(result), result
        
    def get_string_no_punctuation_or_emoji(self, s):
        """去除字符串首尾的空格、标点符号和表情符号"""
        chars = list(s)
        # 处理开头的字符
        start = 0
        while start < len(chars) and self.is_punctuation_or_emoji(chars[start]):
            start += 1
        # 处理结尾的字符
        end = len(chars) - 1
        while end >= start and self.is_punctuation_or_emoji(chars[end]):
            end -= 1
        return "".join(chars[start : end + 1])
    
    def is_punctuation_or_emoji(self, char):
        """检查字符是否为空格、指定标点或表情符号"""
        # 定义需要去除的中英文标点（包括全角/半角）
        punctuation_set = {
            "，",
            ",",  # 中文逗号 + 英文逗号
            "。",
            ".",  # 中文句号 + 英文句号
            "！",
            "!",  # 中文感叹号 + 英文感叹号
            "-",
            "－",  # 英文连字符 + 中文全角横线
            "、",  # 中文顿号
        }
        if char.isspace() or char in punctuation_set:
            return True
        # 检查表情符号（保留原有逻辑）
        code_point = ord(char)
        emoji_ranges = [
            (0x1F600, 0x1F64F),
            (0x1F300, 0x1F5FF),
            (0x1F680, 0x1F6FF),
            (0x1F900, 0x1F9FF),
            (0x1FA70, 0x1FAFF),
            (0x2600, 0x26FF),
            (0x2700, 0x27BF),
        ]
        return any(start <= code_point <= end for start, end in emoji_ranges)

